/**
 * @Project Name :  als-rpc-client
 * @Package Name :  com.alvis.springscan
 * @Description :  TODO
 * @author :  Alvis
 * @Creation Date:  2018-07-04 9:00 AM
 * @ModificationHistory Who    When    What
 * --------  ---------  --------------------------
 */
package com.alvis.container.spring;

import com.alvis.config.RpcConfig;
import com.alvis.container.RpcServiceProxy;
import com.alvis.container.RpcService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.lang.annotation.Annotation;
import java.lang.reflect.Proxy;

/**
 * @author :  Alvis
 * @Description :  TODO
 * @Creation Date:  2018-07-04 9:00 AM
 */
public class RpcServiceBeanRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, BeanFactoryAware {
    private Environment environment;
    private BeanFactory beanFactory;


    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false, environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                AnnotationMetadata metadata = beanDefinition.getMetadata();
                return metadata.isIndependent() && metadata.isInterface();
            }
        };
        provider.addIncludeFilter(new AnnotationTypeFilter(RpcService.class));

        for (BeanDefinition beanDefinition : provider.findCandidateComponents(RpcConfig.getBasePackage())) {
            try {
                String beanName = beanDefinition.getBeanClassName();
                Class<?> clazz = Class.forName(beanName);
                Annotation[] annotations = clazz.getAnnotations();
                for (Annotation annotation : annotations) {
                    if (annotation instanceof RpcService) {
                        RpcServiceProxy rpcBeanProxy = new RpcServiceProxy(clazz);
                        Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, rpcBeanProxy);
                        String value = ((RpcService) annotation).value();
                        ((DefaultListableBeanFactory) this.beanFactory).registerSingleton(value, proxy);
                        break;
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

}
